# 导入模块
from machine import Timer,SoftI2C, Pin
import utime
import network
from simple import MQTTClient
import random
import dht
from ssd1306 import SSD1306_I2C

# 路由器WIFI账号和密码
WIFI_SSID = "10-317no.2"
WIFI_PASSWORD = "66778899"
# MQTT服务器配置
MQTT_BROKER="192.168.1.100"
MQTT_TOPIC = "study/sensor/data"
MQTT_USER=''
MQTT_PASSWORD=''
MQTT_CLIENTID = "test_" + str(random.randrange(1000, 10000))
# 初始化全局变量
wlan = network.WLAN(network.STA_IF)  # STA模式
client = None
mqtt_connected = False
myTimer = None
# 初始化 DHT11 传感器引脚
dht_pin = Pin(27, Pin.IN)
sensor = dht.DHT11(dht_pin)

# OLED 显示器初始化
i2c = SoftI2C(sda=Pin(23), scl=Pin(22))
oled = SSD1306_I2C(128, 64, i2c)

# 存储上次读取的数据
last_temperature = None
last_humidity = None
def connect_wifi(WIFI_SSID, WIFI_PASSWORD):   
    if not wlan.isconnected():
        print("Connecting to network...")
        wlan.active(True)
        while not wlan.isconnected():
            try:
                wlan.connect(WIFI_SSID, WIFI_PASSWORD)
                # 短暂等待连接建立
                utime.sleep(1)
            except Exception as e:
                # 捕获错误，并等待一段时间后再重试
                print(f"Connection failed: {e}, retrying...")
                utime.sleep(1)  # 等待1秒后重试
    print("Network connected.", wlan.ifconfig())

def connect_mqtt():
    global client,mqtt_connected,myTimer
    if wlan.isconnected() == False :
        return
    try:
        # 如果是重连，先断开旧连接
        if client is not None:
            client.disconnect()
        if myTimer is not None:  # 释放旧定时器
            myTimer.deinit()
        client = MQTTClient(MQTT_CLIENTID, MQTT_BROKER, 1883, MQTT_USER, MQTT_PASSWORD)
        client.set_callback(mqtt_callback)
        client.connect()
        mqtt_connected = True
        print("MQTT connected")
        client.subscribe(MQTT_TOPIC)
        print(f"Subscribed to topic: {MQTT_TOPIC}")
        # 初始化定时器，定期检查消息
        myTimer = Timer(0)
        myTimer.init(period=100, mode=Timer.PERIODIC, callback=mqtt_recv)
    except Exception as e:
        mqtt_connected = False
        print(f"MQTT connection failed: {e}, retrying in 1 second...")
        utime.sleep(1)
        connect_mqtt()  # 重试连接

# 发布数据任务
def mqtt_send(TOPIC, msg):
    global client, mqtt_connected
    if client is not None and mqtt_connected:
        try:
            client.publish(TOPIC, msg)
            print(f"Message sent: {msg} to topic: {topic}")
        except Exception as e:
            print(f"Failed to publish message: {e}")
    else:
        print("MQTT client is not connected.")

# 接收数据任务
def mqtt_recv(myTimer):
    global client,mqtt_connected,wlan
    if wlan.isconnected():
        if mqtt_connected:
            try:
                client.check_msg()
            except Exception as e:
                print(f"MQTT check_msg failed: {e}")
                mqtt_connected = False
        else:
            print("MQTT connection lost, Reconnecting...")
            connect_mqtt()  # 尝试重连
    else:
        print("WiFi disconnected. Reconnecting...")
        connect_wifi(WIFI_SSID, WIFI_PASSWORD)  # 尝试重连WiFi
        myTimer.deinit()


# 设置 MQTT 回调函数,定时执行
def mqtt_callback(topic, msg):
    print("topic: {}".format(topic))
    print("msg: {}".format(msg))
    if msg==b'1':
        oled.text("Mode 1", 0, 32)
        oled.show()
    if msg==b'2':
        oled.text("Mode 2", 0, 32)
        oled.show()
    

# 检查并保持WiFi连接
def wifi_check():
    global wlan
    if not wlan.isconnected():
        print("WiFi disconnected. Reconnecting...")
        connect_wifi(WIFI_SSID, WIFI_PASSWORD)
 
 # 检查并保持MQTT连接
def mqtt_check():
    global mqtt_connected
    if client is not None and not mqtt_connected:
        print("MQTT connection lost. Reconnecting...")
        connect_mqtt()

# 初始化 OLED 显示
def init_display():
    oled.fill(0)
    oled.text("Initializing...", 0, 0)
    oled.text(f"WiFi: {WIFI_SSID}", 0, 16)
    oled.show()

# 读取 DHT11 传感器数据
def read_dht_data():
    try:
        sensor.measure()
        T = sensor.temperature()
        H = sensor.humidity()
        if T is None or H is None:
            print("DHT11传感器检测失败!")
            return None, None
        else:
            return T, H
    except OSError as e:
        print("读取传感器失败，错误信息：", e)
        return None, None

# 更新 OLED 显示
def update_display(temperature, humidity):
    oled.fill(0)
    oled.text("Temp2: {:.1f} C".format(temperature), 0, 0)
    oled.text("Humi2: {:.1f}%".format(humidity), 0, 16)
    oled.show()

def myInit():
    init_display()
    connect_wifi(WIFI_SSID, WIFI_PASSWORD)  # 初始化WiFi连接
    connect_mqtt()  # 初始化MQTT连接
    
# 主循环，保持网络连接并处理任务
def loop():
    global wlan,last_temperature,last_humidity
    while True:
        try:
            wifi_check()  # 检查WiFi连接
            mqtt_check()  # 检查MQTT连接
            temperature, humidity = read_dht_data()
        
            # 检查数据是否变化
            if temperature is not None and humidity is not None:
                msg="Temp: {:.1f} C".format(temperature)+",Humi: {:.1f}%".format(humidity)
                mqtt_send(MQTT_TOPIC,msg)
                if temperature != last_temperature or humidity != last_humidity:
                    update_display(temperature, humidity)
                    last_temperature = temperature
                    last_humidity = humidity
                    print("Updated display with new data.")
            utime.sleep(2)  # 稍微延迟，避免频繁检查
        except Exception as e:
            print("主循环，错误信息：", e)

    
# 程序入口
if __name__ == "__main__":
    myInit()
    loop()

